import BaseStation from './BaseStation'
import Product from './Product'
import SimulationSpeed from '../core/SimulationSpeed'
import { getPointAndAngleAt } from '../utils/svgUtils'
import { messageTransfer } from '../messaging/MessageTransfer'
import { addReadyProduct, getReadyProduct } from '../core/ReadyProducts'
import { currentTime } from '../core/SimulationClock'
import { simController } from '../simulation/SimController'

class Conveyor extends BaseStation {
  path: string
  speed: number
  length: number
  status: 'idle' | 'processing' = 'idle'
  startPointer: number = 0
  endPointer: number = 1
  readyList: Product[] = []
  productLinkedList: { pointer: number; product: Product }[] = []
  reachProduct: null | Product = null

  constructor(id: string, name: string, path: string, speed: number, length: number) {
    super(id, name, 0, 0, 0, 0)
    this.path = path
    this.speed = speed
    this.length = length
  }

  public canReceiveProduct(id: string, product: Product): boolean {
    const productWidth = product.width
    if (this.productLinkedList.length === 0) {
      return true
    }

    const startItem = this.productLinkedList[0]
    const startPointer = startItem.pointer - productWidth / 2 / this.length
    const remainingLength = startPointer * this.length
    if (remainingLength < productWidth) {
      return false
    } else {
      return true
    }
  }

  //接受就绪产品
  receiveReadyProduct(productId: string): void {
    this.readyProduct = productId

    const product = getReadyProduct(productId)
    if (!product) {
      this.setStatus('idle')
      console.log(`[${currentTime}] ❌ ${productId} 没有发现`)
      return
    }
    console.log(`[${currentTime}] ${product.id} 到达 --> ${this.name}`)
    product.setFrom(this.id)
    this.onProductReceived(product)
  }

  public onProductReceived(product: Product): void {
    const initPosition = this.startPointer + product.width / 2 / this.length
    const position = getPointAndAngleAt(this.path, initPosition)
    messageTransfer('product', 'transport', {
      targetId: this.id,
      productId: product.id,
      x: position.x,
      y: position.y,
      angle: position.angle,
      duration: 0
    })
    this.readyList.push(product)
    // this.putInProduct(product)

    if (this.status === 'idle') {
      this.setStatus('processing')
      this.moving()
    }
  }

  //开始移动
  private moving(): void {
    if (this.status !== 'processing') return
    if (simController.getStatus() !== 'running') return

    //先派发产品
    this.tryDispatchCurrentProduct()
    //在拿首位产品
    const firstProduct = this.readyList.shift()
    if (firstProduct) {
      this.putInProduct(firstProduct)
    }
    if (this.productLinkedList.length === 0) {
      this.setStatus('idle')
      return
    }

    //算出移动距离
    const distance = ((this.speed / 20) * SimulationSpeed.getSpeed) / this.length
    for (let i = this.productLinkedList.length - 1; i >= 0; i--) {
      const item = this.productLinkedList[i]
      //下一个产品的位置
      let nextProductPointer = null as null | number
      if (i === this.productLinkedList.length - 1) {
        nextProductPointer = this.endPointer - item.product.width / 2 / this.length
      } else {
        nextProductPointer =
          this.productLinkedList[i + 1].pointer -
          (item.product.width / 2 / this.length +
            this.productLinkedList[i + 1].product.width / 2 / this.length)
      }

      //计算间距
      const pointerDistance = nextProductPointer - item.pointer

      //如果间距大于移动距离，则移动
      if (pointerDistance > distance) {
        this.productLinkedList[i].pointer += distance
        //计算移动时间
        // const duration = (distance * this.length) / ((this.speed / 20) * SimulationSpeed.getSpeed)
        const position = getPointAndAngleAt(this.path, this.productLinkedList[i].pointer)
        messageTransfer('product', 'transport', {
          targetId: this.id,
          productId: item.product.id,
          x: position.x,
          y: position.y,
          angle: position.angle,
          duration: 0
        })
      }
      //如果间距小于移动距离，则需要和下一个产品紧贴，并计算好移动距离和时间
      else {
        const remainingSpacing = ((): number => {
          if (i === this.productLinkedList.length - 1) {
            const spacing = this.endPointer - (item.pointer + item.product.width / 2 / this.length)

            this.reachProduct = item.product
            return spacing
          } else {
            //下一个产品
            const nextProduct = this.productLinkedList[i + 1]
            //算出剩余间距
            const spacing =
              nextProduct.pointer -
              nextProduct.product.width / 2 / this.length -
              (item.pointer + item.product.width / 2 / this.length)
            return spacing
          }
        })()

        if (remainingSpacing < 0.001) continue

        this.productLinkedList[i].pointer += remainingSpacing
        //计算移动时间
        // const duration =
        //   (remainingSpacing * this.length) / ((this.speed / 20) * SimulationSpeed.getSpeed)
        const position = getPointAndAngleAt(this.path, this.productLinkedList[i].pointer)
        messageTransfer('product', 'transport', {
          targetId: this.id,
          productId: item.product.id,
          x: position.x,
          y: position.y,
          angle: position.angle,
          duration: 0
        })
      }
    }

    setTimeout(() => {
      this.moving()
    }, 50)
  }

  public tryDispatchCurrentProduct(): void {
    if (this.reachProduct === null) return
    const productId = this.reachProduct.id
    for (const next of this.nextStations) {
      if (next.canReceiveProduct(this.id, this.reachProduct)) {
        addReadyProduct(this.reachProduct)
        next.receiveReadyProduct(productId)
        this.reachProduct = null
        this.removeProduct()
        break
      }
    }
  }

  protected setStatus(status: 'idle' | 'processing'): void {
    this.status = status
  }

  private putInProduct(product: Product): void {
    const initPosition = this.startPointer + product.width / 2 / this.length
    this.productLinkedList.unshift({ pointer: initPosition, product })
  }
  private removeProduct(): void {
    //移除最后一个元素
    this.productLinkedList.pop()
  }
}

export default Conveyor
